package com.path.planning.util.path.entity;

import org.jgrapht.EdgeFactory;
import org.jgrapht.Graph;
import org.jgrapht.GraphType;
import org.jgrapht.graph.DefaultWeightedEdge;

import java.util.Collection;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * 自定义路网拓扑图，带避让区逻辑
 *
 * @param <V>
 * @param <E>
 */
public class CustomGraphWrapper<V, E extends DefaultWeightedEdge> implements Graph<V, E> {
    private final Graph<V, E> originGraph;
    private final Set<E> avoidEdges;

    public CustomGraphWrapper(Graph<V, E> originGraph, Set<E> avoidEdges) {
        this.originGraph = originGraph;
        this.avoidEdges = avoidEdges;
    }

    @Override
    public Set<E> getAllEdges(V v, V v1) {
        return originGraph.getAllEdges(v, v1).stream()
                .filter(e -> !avoidEdges.contains(e))
                .collect(Collectors.toSet());
    }

    @Override
    public E getEdge(V v, V v1) {
        E edge = originGraph.getEdge(v, v1);
        return avoidEdges.contains(edge) ? null : edge;
    }

    @Override
    public EdgeFactory<V, E> getEdgeFactory() {
        return originGraph.getEdgeFactory();
    }

    @Override
    public Supplier<V> getVertexSupplier() {
        return originGraph.getVertexSupplier();
    }

    @Override
    public Supplier<E> getEdgeSupplier() {
        return originGraph.getEdgeSupplier();
    }

    @Override
    public E addEdge(V v, V v1) {
        return originGraph.addEdge(v, v1);
    }

    @Override
    public boolean addEdge(V v, V v1, E e) {
        return originGraph.addEdge(v, v1, e);
    }

    @Override
    public V addVertex() {
        return originGraph.addVertex();
    }

    @Override
    public boolean addVertex(V v) {
        return originGraph.addVertex(v);
    }

    @Override
    public boolean containsEdge(V v, V v1) {
        return originGraph.containsEdge(v, v1) && !avoidEdges.contains(originGraph.getEdge(v, v1));
    }

    @Override
    public boolean containsEdge(E e) {
        return originGraph.containsEdge(e) && !avoidEdges.contains(e);
    }

    @Override
    public boolean containsVertex(V v) {
        return originGraph.containsVertex(v);
    }

    @Override
    public Set<E> edgeSet() {
        return originGraph.edgeSet().stream()
                .filter(e -> !avoidEdges.contains(e))
                .collect(Collectors.toSet());
    }

    @Override
    public int degreeOf(V v) {
        return originGraph.degreeOf(v);
    }

    @Override
    public Set<E> edgesOf(V v) {
        return originGraph.edgesOf(v).stream().filter(e -> !avoidEdges.contains(e)).collect(Collectors.toSet());
    }

    @Override
    public int inDegreeOf(V v) {
        return originGraph.inDegreeOf(v);
    }

    @Override
    public Set<E> incomingEdgesOf(V v) {
        return originGraph.incomingEdgesOf(v).stream().filter(e -> !avoidEdges.contains(e)).collect(Collectors.toSet());
    }

    @Override
    public int outDegreeOf(V v) {
        return originGraph.outDegreeOf(v);
    }

    @Override
    public Set<E> outgoingEdgesOf(V v) {
        return originGraph.outgoingEdgesOf(v).stream().filter(e -> !avoidEdges.contains(e)).collect(Collectors.toSet());
    }

    @Override
    public boolean removeAllEdges(Collection<? extends E> collection) {
        return originGraph.removeAllEdges(collection);
    }

    @Override
    public Set<E> removeAllEdges(V v, V v1) {
        return originGraph.removeAllEdges(v, v1);
    }

    @Override
    public boolean removeAllVertices(Collection<? extends V> collection) {
        return originGraph.removeAllVertices(collection);
    }

    @Override
    public E removeEdge(V v, V v1) {
        return originGraph.removeEdge(v, v1);
    }

    @Override
    public boolean removeEdge(E e) {
        return originGraph.removeEdge(e);
    }

    @Override
    public boolean removeVertex(V v) {
        return originGraph.removeVertex(v);
    }

    @Override
    public Set<V> vertexSet() {
        return originGraph.vertexSet();
    }

    @Override
    public V getEdgeSource(E e) {
        return avoidEdges.contains(e) ? null : originGraph.getEdgeSource(e);
    }

    @Override
    public V getEdgeTarget(E e) {
        return avoidEdges.contains(e) ? null : originGraph.getEdgeTarget(e);
    }

    @Override
    public GraphType getType() {
        return originGraph.getType();
    }

    @Override
    public double getEdgeWeight(E e) {
        return avoidEdges.contains(e) ? Double.NEGATIVE_INFINITY : originGraph.getEdgeWeight(e);
    }

    @Override
    public void setEdgeWeight(E e, double v) {
        originGraph.setEdgeWeight(e, v);
    }
}
